package io.github.source.media.bean;

import android.net.Uri;

import com.github.catvod.crawler.Spider;
import com.github.catvod.net.OkHttp;
import com.orhanobut.logger.Logger;

import java.io.IOException;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.collection.ArrayMap;
import io.github.source.Sniffer;
import io.github.source.Source;
import io.github.source.bean.Site;
import io.github.source.bean.Url;
import io.github.source.config.VodConfig;
import io.github.source.parse.ParseJob;
import okhttp3.Call;
import okhttp3.Response;

/**
 * @ClassName: MediaPlayProvider
 * @Description: (获取播放信息并解析播放地址)
 * @author: huangrongcai
 * @date: 2024/6/21
 * @Copyright: 黄嵘才（HuangRc)
 */
interface MediaPlayProvider {
    /**
     * 获取媒体播放信息。
     *
     * @param mediaQuery 播放器环境信息，查询参数等。
     * @param video      媒体对象。
     * @return 包含媒体播放信息的MediaResult对象，永远不会为null。
     */
    @NonNull
    MediaResult<MediaPlay> getMediaPlayback(MediaQuery mediaQuery, MediaBean video) throws Exception;

    interface Factory {
        MediaPlayProvider newCall(MediaQuery query);
    }

    static MediaPlayProvider create() {
        return new Impl();
    }

    /**
     * @ClassName: MediaPlayProviderImpl
     * @Description: (获取播放信息)
     * @author: huangrongcai
     * @date: 2024/6/21
     * @Copyright: 黄嵘才（HuangRc)
     */
    static class Impl implements MediaPlayProvider {
        private static final String TAG = "Source.Media.Play.Provider.default";

        @NonNull
        @Override
        public MediaResult<MediaPlay> getMediaPlayback(MediaQuery query, MediaBean video) {
            MediaResult<MediaPlay> result = null;
            try {
                // 获取播放信息
                MediaPlay play = fetchMediaPlay(query);

                // 解析（处理）播放信息
                result = parseMediaPlay(query, play);

                return result;
            } catch (Exception e) {
                Logger.t(TAG).e(e, "获取媒体播放数据异常");
                return MediaResult.error(500).message("获取媒体播放数据异常:" + e);
            } finally {
                loggerMediaPlay("返回", result);
            }

        }

        //记录日志
        private void loggerOnQuery(Site site, MediaQuery query) {
            Logger.t(TAG).d(" --> 请求播放信息 "
                    + "site=" + site + "\n"
                    + "query=" + query);
        }

        private void loggerOnQueryReturn(MediaPlay play) {
            //日志
            Logger.t(TAG).d(" <-- 请求播放信息 play=" + play);
        }

        /**
         * 输出播放信息的日志数据
         *
         * @param playResult 播放信息
         */
        private void loggerMediaPlay(String msg, MediaResult<MediaPlay> playResult) {
            if (playResult != null) {
                MediaPlay play = playResult.getData();
                StringBuilder sb = new StringBuilder();
                sb.append(" <-- 播放 ");
                sb.append(msg);
                if (play != null) {
                    sb.append("\n").append("url=").append(play.getPlayUrl());
                    sb.append("\n").append("header=" + play.getHeader());
                }
                Logger.t(TAG).d(sb);
            } else {
                Logger.t(TAG).d("播放 play=" + null);
            }
        }

        private MediaPlay getMediaPlay(MediaPlay play, MediaQuery query) {
            //从playUrl中获取解析出可播放的
            String url = query.getPlayUrl();
            if (Sniffer.isVideoFormat(url)) {
                String playUrl = "";
                playUrl = Sniffer.getVideoUrl(url);
                String siteKey = query.getSiteKey();
                Site site = VodConfig.get().getSite(siteKey);
                if (play == null) {
                    play = MediaPlay.empty();
                }
                play.setPlayUrl(playUrl);
                play.setHeaders(play, site.getHeader());
                return play;
            }

            return play;

        }


        public MediaPlay fetchMediaPlay(MediaQuery query) throws Exception {
            /*query 里的地址是可能是播放的地址？1，优先检查query.playUrl是不是可以直接播放*/
            Source.get().stop();

            String siteKey = query.getSiteKey();
            Site site = VodConfig.get().getSite(siteKey);

            loggerOnQuery(site, query);
            MediaPlay play = null;

            if (site.getType() == 3) {
                play = getPlayContentBySpider(site, query);
            } else if (site.getType() == 4) {
                play = getPlayContentByHttp(site, query);
            } else if (site.isEmpty() && "push_agent".equals(siteKey)) {/*推送的播放源*/
                play = getPlayContentByPush(site, query);
            } else {
                play = getPlayContentByDefault(site, query);
            }
        /*几种常见playUrl(要转义http)
         * 1.NBY-2210c8758b4a0c805bea6818e421fa5b|http://121.62.61.51:6888/api/?key=BxzJDoznSIoiPuDrRm&url=
         * https://v.cdnlz3.com/20240718/24900_41aca672/index.m3u8|http://43.248.186.15:8082/jx/?url=
         * https://c1.rrcdnbf3.com/video/tangchaoguishiluzhixixing/第01集/index.m3u8|http://43.248.186.15:8082/jx/?url=
         * http://www.iqiyi.com/v_186njga2r64.html|https://cdn.suxun.site/api/?key=vV2dLM1za9kCV2LHTr&url=
         *Feiyun-oSoVRf|2FVPhr7aQjWE4uW0|2Fwr5ai9DeU7o2mlwFQumWE2gL20zEGYck|2BZOsM|2FFzsw5LdqKwwV|2BSXns|2FC0n5EpDg|3D|3D-FYNB1
         * https://www.tpvod.com/player.html?uri=https%3A%2F%2Fsd8.taopianplay1.com%3A43333%2Fc56b1bc09da3%2FHD%2F2024-07-09%2F15%2F9428ee0cd07c%2Ff7e0dae453eb%2Fplaylist.m3u8
         https://www.brovod.com/play/188267-6-1/
         * data:application/vn....这类好像EXO播放器可以解析，IJK不行。可以通过site 里的playerType = 2
         * 有需要通过WebView解析
         * */

            /*如果Play的播放地址不合规，则从查询里重新获取*/
            if (!Sniffer.isVideoFormat(play.getPlayUrl())) {
                play = getMediaPlay(play, query);
            }

            loggerOnQueryReturn(play);
            return play;
        }

        private String call(Site site, ArrayMap<String, String> params, boolean limit) throws IOException {
            Call call = fetchExt(site, params, limit).length() <= 1000 ? OkHttp.newCall(site.getApi(), site.getHeaders(), params) : OkHttp.newCall(site.getApi(), site.getHeaders(), OkHttp.toBody(params));
            return call.execute().body().string();
        }

        private String fetchExt(Site site, ArrayMap<String, String> params, boolean limit) throws IOException {
            String extend = site.getExt();
            if (extend.startsWith("http")) extend = fetchExt(site);
            if (limit && extend.length() > 1000) extend = extend.substring(0, 1000);
            if (!extend.isEmpty()) params.put("extend", extend);
            return extend;
        }

        private String fetchExt(Site site) throws IOException {
            Response res = OkHttp.newCall(site.getExt(), site.getHeaders()).execute();
            if (res.code() != 200) return "";
            site.setExt(res.body().string());
            return site.getExt();
        }

        //尝试解析(如有必要)
        private MediaResult<MediaPlay> parseMediaPlay(MediaQuery query, MediaPlay play) {
            // 检查 play 是否为空
            if (play == null) {
                Logger.d("MediaPlay is null, skip parsing.");
                return MediaResult.empty().message("MediaPlay is null");
            }
            try {
                if (ParseJob.shouldParseMediaPlay(play)) {
                    Logger.t(TAG).d(" --> 解析播放信息 "
                            + "play=" + play + "\n"
                            + "query=" + query
                    );

                    play = ParseJob.create(play).execute();

                    Logger.t(TAG).d(" <-- 解析播放信息 play=" + play);
                }

                //2再检查播放地址
                if (play != null) {
                    return MediaResult.success(play);
                } else {
                    return MediaResult.empty().message("解析后 MediaPlay 为 null");
                }
            }catch (Exception e){
                Logger.t(TAG).e(e, "解析 MediaPlay 出错");
                return MediaResult.error(500).message("解析失败: ${e.message}");
            }

        }

        /**
         * 从爬虫获取播放信息
         *
         * @param site  Site
         * @param query MediaQuery 参数
         * @return MediaPlay
         * @throws Exception 异常
         */
        private MediaPlay getPlayContentBySpider(Site site, MediaQuery query) throws Exception {
            Spider spider = VodConfig.get().getSpider(site);
            String playFlag = query.getPlayFlag();
            String id = query.getPlayUrl();
            List<String> vipFlag = query.getVipFlag();
            Logger.t(TAG).d(" --> spider Player request:" + " ,spider=" + spider + " ,playFlag=" + playFlag + " ,id=" + id + " ,vipFlag=" + vipFlag);
            String playerContent = spider.playerContent(playFlag, id, vipFlag);

            Logger.t(TAG).d(" <-- spider Player Content:" + playerContent);
            VodConfig.get().setRecent(site);
            //封装播放地址
            MediaPlay play = onReturnContent(query, playerContent);
            ;
            if (play.getFlag() == null || play.getFlag().isEmpty()) {
                play.setFlag(playFlag);
            }
            play.setPlayUrl(Source.get().fetch(play));
            play.setHeaders(play, site.getHeader());/*头信息*/
            play.setKey(site.getKey());

            return play;
        }

        /**
         * 从网络获取播放信息
         *
         * @param site  Site
         * @param query MediaQuery
         * @return MediaPlay
         * @throws Exception 异常
         */
        private MediaPlay getPlayContentByHttp(Site site, MediaQuery query) throws Exception {
            String id = query.getPlayUrl();
            String flag = query.getPlayFlag();
            ArrayMap<String, String> params = new ArrayMap<>();
            params.put("play", id);
            params.put("flag", flag);
            String playerContent = call(site, params, true);/*网络请求*/
            Logger.t(TAG).d("http playerContent:" + playerContent);

            MediaPlay play = MediaPlay.objectFrom(playerContent);
            play.setFlag(flag);
            play.setPlayUrl(Source.get().fetch(play));
            play.setHeaders(play, site.getHeader());

            return play;
        }

        /**
         * 从推送获取
         *
         * @param site  源站
         * @param query 参数
         * @return MediaPlay
         * @throws Exception
         */
        private MediaPlay getPlayContentByPush(Site site, MediaQuery query) throws Exception {
            String id = query.getPlayUrl();
            String flag = query.getPlayFlag();

            MediaPlay play = MediaPlay.objectFrom("");

            play.setParse(0);
            play.setFlag(flag);
            play.setUrl(Url.create().add(id));
            play.setPlayUrl(Source.get().fetch(play));
            play.setHeaders(play, site.getHeader());

            return play;
        }

        /**
         * 从默认获取
         *
         * @param site  Site
         * @param query MediaQuery
         * @return MediaPlay
         * @throws Exception
         */
        private MediaPlay getPlayContentByDefault(Site site, MediaQuery query) throws Exception {
            String id = query.getPlayUrl();
            String flag = query.getPlayFlag();
            Url url = Url.create().add(id);
            String type = Uri.parse(id).getQueryParameter("type");
            if ("json".equals(type)) {
                String rep = OkHttp.newCall(id, site.getHeaders()).execute().body().string();
                url = MediaPlay.objectFrom(rep).getUrl();/*取得播放地址*/
            }

            MediaPlay play = MediaPlay.objectFrom("{}");//直接封装返回
            play.setUrl(url);
            play.setFlag(flag);
            play.setPlayUrl(Source.get().fetch(play));
            play.setHeaders(play, site.getHeader());
            play.setParse(Sniffer.isVideoFormat(url.v()) && play.getPlayUrl().isEmpty() ? 0 : 1);

            return play;
        }

        public MediaPlay onReturnContent(MediaQuery query, String response) {
            //不现的站源返回的数据格式是不一样的。
            MediaPlay play = MediaPlay.objectFrom(response);
            return play;
        }
    }


}
